home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '92 / Hacks ’92 / FinderMenu ƒ / FinderMenu INIT ƒ / FinderMenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-14  |  16.3 KB  |  809 lines  |  [TEXT/KAHL]

  1. /*
  2.  * (C) 1992 SixxHeads Software
  3.  * (C) 1992 Berkeley Systems Inc.
  4.  * 
  5.  * This code is freely distributable, but credit must be given in any
  6.  * derivative work.
  7.  *
  8.  * <Revision History>
  9.  *        04/28/92  smz  Created.
  10.  *        05/16/92  smz  insert the menus around the drawmenu call; avoid flashing
  11.  *      05/18/92  smz  return fnfErr from FSDispatch
  12.  *        05/24/92  smz  adde cursor rotating code (urp!)
  13.  *      06/04/92  smz  add cancelledmenu stuff
  14.  *        06/08/92  smz  added Insert && DeleteMenu patches for hierarchial menus
  15.  *      06/11/92  smz  added script cancelled stuff, use fsspecs for the collection
  16.  *      06/13/92  smz  use Get Info item to determine whether there is any information to collect
  17.  *      <1.0 release>
  18.  */
  19.  
  20. #include <varargs.h>
  21. #include <stdio.h>
  22. #include <stddef.h>
  23. #include <string.h>
  24. #include <Extension.h>
  25. #include <Errors.h>
  26. #include <Patch.h>
  27. #include <GestaltEqu.h>
  28. #include <Exceptions.h>
  29. #include <Traps.h>
  30. #include <Globals.h>
  31. #include <AppleEvents.h>
  32.  
  33. #include <FinderStuff.h>
  34.  
  35. #include "Utils.h"
  36. #include "FinderMenuInterface.h"
  37. #include "MenuList.h"
  38. #include "DrawstringHack.h"
  39.  
  40. #include "Patches.h"
  41.  
  42. #define cDefaultFileMenuID    1252
  43. #define cContinueAlert        0x177d
  44. #define cLastAlert            0x177a
  45.  
  46. #define cNumCursors            4
  47. #define cFirstCursorID        128
  48.  
  49. /*
  50.  * Local Globals
  51.  */
  52. static Boolean theWorldInit;
  53. static unsigned long theGetInfoItem;
  54. //static unsigned long theOpenItem;
  55.  
  56. static short theRunningCount;
  57.  
  58. static Boolean theFileListGood;
  59. static AEDescList theFileList;
  60.  
  61. static Boolean theMenuBarDirty;
  62.  
  63. static short theDrawingHappening;    // for drawstring, stringwidth
  64.  
  65. static Boolean theInfoValid;
  66. static FSSpec theInfoFSSpec;
  67. static OSType theCreator;
  68.  
  69. static AlertPatch *theAlertPatch;
  70. static FSDispatchPatch *theFSDispatchPatch;
  71. static DrawStringPatch *theDrawStringPatch;
  72. static StringWidthPatch *theStringWidthPatch;
  73. static SetCursorPatch *theSetCursorPatch;
  74. static PostEventPatch *thePostEventPatch;
  75. static ParamTextPatch *theParamTextPatch;
  76.  
  77. static Boolean theBeachBallRolling = false;
  78. static Cursor theRollingCursors[cNumCursors];
  79. static Boolean theCmdPeriodHit;
  80.  
  81. /***************************************************************************/
  82.  
  83. static void InitWorld(void)
  84. {
  85.     GetFinderItem('sinf', cDefaultFileMenuID, &theGetInfoItem);
  86. //    GetFinderItem('sope', cDefaultFileMenuID, &theOpenItem);
  87.     theWorldInit = true;
  88. }
  89.  
  90. static Boolean LoadCursors(void)
  91. {
  92.     reg short i;
  93.     
  94.     for (i = 0;  i < cNumCursors;  i++) {
  95.         CursHandle hRes = GetCursor(cFirstCursorID + i);
  96.         if (hRes == nil)
  97.             return false;
  98.         theRollingCursors[i] = **hRes;
  99.         ReleaseResource(hRes);
  100.     }
  101.     return true;
  102. }
  103.  
  104. static void PushDrawing()
  105. {        
  106.     if (theDrawingHappening++ == 0) {        
  107.         theDrawStringPatch->Enable();
  108.         theStringWidthPatch->Enable();
  109.     }
  110. }
  111.  
  112. static void PopDrawing()
  113. {
  114.     if (--theDrawingHappening == 0) {
  115.         theDrawStringPatch->Disable();
  116.         theStringWidthPatch->Disable();
  117.     }
  118. }
  119.  
  120. static void StartCursor()
  121. {
  122.     theBeachBallRolling = true;
  123.     theSetCursorPatch->Enable();
  124. }
  125.  
  126. static void EndCursor()
  127. {
  128.     theBeachBallRolling = false;
  129.     theSetCursorPatch->Disable();
  130. }
  131.  
  132. static Cursor *GetNextCursor()
  133. {
  134.     static short theBeachBallIndex = 0;
  135.     reg Cursor *pCurs = &theRollingCursors[theBeachBallIndex++];
  136.     if (theBeachBallIndex >= cNumCursors)
  137.         theBeachBallIndex = 0;
  138.     return pCurs;
  139. }
  140.  
  141. /***************************************************************************/
  142.  
  143. static Boolean CheckForDialogs()
  144. {
  145.     if (WindowList != nil)
  146.         if (WindowList->windowKind == dialogKind)
  147.             return false;
  148.  
  149.     return true;
  150. }
  151.  
  152. DrawMenuBarPatch::DrawMenuBarPatch()
  153. {
  154.     GenericPatch::InitGenericPatch(_DrawMenuBar, 0);
  155.     Install();
  156. }
  157.  
  158. void DrawMenuBarPatch::Behavior()
  159. {    
  160.     Disable();
  161.         
  162.     if (IsFinderRunning() && CheckForDialogs()) {
  163.         reg DrawMenuBarProcPtr oldDrawMenuBar = (DrawMenuBarProcPtr) itsOld;
  164.         
  165.         PushDrawing();
  166.  
  167.         InsertAllMenus(true);
  168.         
  169. #if !__option(a4_globals)
  170.         {
  171.             long oldA5 = SetA5((long) itsFrame->ra5);
  172. #endif
  173.         
  174.             (*oldDrawMenuBar)();
  175.  
  176. #if !__option(a4_globals)
  177.             (void) SetA5(oldA5);
  178.         }
  179. #endif
  180.         AbortTrap();
  181.  
  182.         RemoveAllMenus(true);
  183.         
  184.         PopDrawing();
  185.     }
  186.  
  187.     Enable();
  188. }
  189.  
  190. /***************************************************************************/
  191.  
  192. static void ActivateCollection()
  193. {
  194.     if (theFileListGood) {
  195. #ifdef DEBUG
  196.         DebugStr("\pnobody got the mail!");
  197. #endif
  198.         SysBeep(1);    // nobody picked up their mail!
  199.         AEDisposeDesc(&theFileList);
  200.     }
  201.     theFileListGood = true;
  202.     theAlertPatch->Enable();
  203.     theFSDispatchPatch->Enable();
  204.     thePostEventPatch->Enable();
  205.     theParamTextPatch->Enable();
  206.     theInfoValid = false;
  207.     theCmdPeriodHit = false;
  208.     StartCursor();
  209. }
  210.  
  211.  
  212. static void EndCollection(Boolean successful)
  213. {
  214.     if (theFileListGood) {
  215.         if (successful)
  216.             SendMenuHitInfo(theCreator, &theFileList);
  217.         else
  218.             DeleteMenuHitInfo(theCreator);
  219.  
  220.         AEDisposeDesc(&theFileList);
  221.  
  222.         EndCursor();
  223.     }
  224.     
  225.     theCreator = 0;
  226.     theFileListGood = false;
  227.     theCmdPeriodHit = false;
  228.  
  229.     theAlertPatch->Disable();
  230.     theFSDispatchPatch->Disable();
  231.  
  232. // we're trying turning this off when the client finishes 
  233. //    thePostEventPatch->Disable();    // remindsmz: turn off at endscript time?
  234.  
  235.     theInfoValid = false;
  236. }
  237.  
  238. static long HandleMenuResult(unsigned long result)
  239. {
  240.     if (! theFileListGood)
  241.         if (OwnedMenuHit(result, &theCreator, &theFileList)) {
  242.             ActivateCollection();
  243.             if (! IsItemEnabled(theGetInfoItem)) {
  244.                 EndCollection(true);    // nothing to collect!
  245.                 return 0;
  246.             }
  247.             return theGetInfoItem;
  248.         }
  249.  
  250.     return result;
  251. }
  252.  
  253. /***************************************************************************/
  254.  
  255. MenuSelectPatch::MenuSelectPatch()
  256. {
  257.     GenericPatch::InitGenericPatch(_MenuSelect, offsetof(MenuSelectParameters, itsResult));
  258.     Install();
  259. }
  260.  
  261. void MenuSelectPatch::Behavior()
  262. {
  263.     Disable();
  264.  
  265.     if (IsFinderRunning() && CheckForDialogs()) {
  266.         reg MenuSelectParameters* params = (MenuSelectParameters*) itsFrame->parameters;
  267.         reg MenuSelectProcPtr oldMenuSelect = (MenuSelectProcPtr) itsOld;
  268.  
  269.         PushDrawing();
  270.  
  271.         InsertAllMenus(false);
  272.         
  273.         {
  274. #if !__option(a4_globals)
  275.             long oldA5 = SetA5((long) itsFrame->ra5);
  276. #endif
  277.         
  278.             params->itsResult = (*oldMenuSelect)(params->itsStartPt);
  279.  
  280. #if !__option(a4_globals)
  281.             (void) SetA5(oldA5);
  282. #endif
  283.         }
  284.         
  285.         params->itsResult = HandleMenuResult(params->itsResult);
  286.  
  287.         AbortTrap();
  288.         
  289.         RemoveAllMenus(false);
  290.         
  291.         PopDrawing();
  292.     }
  293.  
  294.     Enable();
  295. }
  296.  
  297. /****************************************************************************/
  298.  
  299. MenuKeyPatch::MenuKeyPatch()
  300. {
  301.     GenericPatch::InitGenericPatch(_MenuKey, offsetof(MenuKeyParameters, itsResult));
  302.     Install();
  303. }
  304.  
  305. void MenuKeyPatch::Behavior()
  306. {
  307.     Disable();
  308.     
  309.     if (IsFinderRunning() && CheckForDialogs()) {
  310.         reg MenuKeyParameters* params = (MenuKeyParameters*) itsFrame->parameters;
  311.         reg MenuKeyProcPtr oldMenuKey = (MenuKeyProcPtr) itsOld;
  312.         
  313.         PushDrawing();
  314.  
  315.         InsertAllMenus(false);
  316.  
  317.         {
  318. #if !__option(a4_globals)
  319.             long oldA5 = SetA5((long) itsFrame->ra5);
  320. #endif
  321.             params->itsResult = (*oldMenuKey)(params->itsKey);
  322.  
  323. #if !__option(a4_globals)
  324.             (void) SetA5(oldA5);
  325. #endif
  326.         }
  327.  
  328.         params->itsResult = HandleMenuResult(params->itsResult);
  329.  
  330.         AbortTrap();
  331.  
  332.         RemoveAllMenus(false);
  333.  
  334.         PopDrawing();
  335.     }
  336.  
  337.     Enable();
  338. }
  339.  
  340. /***************************************************************************/
  341.  
  342. FSDispatchPatch::FSDispatchPatch()
  343. {
  344.     GenericPatch::InitGenericPatch(0xa260, 0);
  345.     Install();
  346.     Disable();
  347. }
  348.  
  349. void FSDispatchPatch::Behavior()
  350. {    
  351.     Disable();
  352.  
  353.     if (theFileListGood 
  354.     && (itsFrame->rd0 == 9L) 
  355.     && ((itsFrame->rd1 & 0xffff) == 0xa260L) 
  356.     && IsFinderRunning()) {
  357.         reg FSDispatchProcPtr oldFSDispatch = (FSDispatchProcPtr) itsOld;
  358.         reg PatchFrame *frame = itsFrame;
  359.                 
  360.         /* need to save lots of registers around this OSTrap */
  361.         asm {
  362.             movem.l    frame->rd0,d0-d2/a0-a1
  363.             movem.l    d3-d7/a2-a5,-(sp)
  364.         }
  365.  
  366.         (*oldFSDispatch)();
  367.  
  368.         asm {
  369.             movem.l    (sp)+,d3-d7/a2-a5
  370.             movem.l    d0-d2/a0-a1,frame->rd0
  371.         }
  372.  
  373.         AbortTrap();
  374.  
  375. #define fpb    ((HFileInfo*) frame->ra0)
  376. #define dpb ((DirInfo*) frame->ra0)
  377.  
  378.         if (fpb->ioNamePtr != nil)
  379.             if (fpb->ioNamePtr[0] != 0) {
  380.                 itsFrame->rd0 = fnfErr;    // cause an error, hence an alert
  381.                 
  382.                 theInfoFSSpec.vRefNum = fpb->ioVRefNum;
  383.                 theInfoFSSpec.parID = dpb->ioDrParID;
  384.                 copystring(fpb->ioNamePtr, theInfoFSSpec.name);
  385.                 
  386.                 theInfoValid = true;
  387.             }
  388. #undef fpb
  389. #undef dpb
  390.     }
  391.     if (! theInfoValid)
  392.         Enable();
  393. }
  394.  
  395. /***************************************************************************/
  396.  
  397. void AlertPatch::AlertPatch()
  398. {
  399.     GenericPatch::InitGenericPatch(_Alert, offsetof(AlertPatchParameters, itsResult));
  400.     Install();
  401. }
  402.  
  403. void AlertPatch::Behavior()
  404. {
  405.     Disable();
  406.  
  407.     if (theFileListGood && IsFinderRunning()) {
  408.         reg AlertPatchParameters *parms = (AlertPatchParameters*) itsFrame->parameters;
  409.  
  410.         if (theInfoValid && ! theCmdPeriodHit) {
  411.             AEDesc pathDesc;
  412.  
  413.             theInfoValid = false;
  414.             
  415.             pathDesc.descriptorType = typeFSS;
  416.             if (AEPutPtr(&theFileList, 0, typeFSS, (void*) &theInfoFSSpec, sizeof(theInfoFSSpec)) != noErr)
  417.                 theCmdPeriodHit = true;
  418.         }
  419.  
  420.         if (theCmdPeriodHit) {
  421.             EndCollection(false);
  422.             if (parms->itsID == cContinueAlert)
  423.                 parms->itsResult = 2;    // stop button - no more collection
  424.             InitCursor();
  425.             theMenuBarDirty = true;
  426.         } else if (parms->itsID == cLastAlert) {
  427.             EndCollection(true);
  428.         } else if (parms->itsID == cContinueAlert) {
  429.             theFSDispatchPatch->Enable();
  430.             parms->itsResult = 1; /* hit continue button */
  431.         } else {
  432. #ifdef DEBUG
  433.             DebugStr("\pSomething strange in the Finder; don't use FinderMenus!!.");
  434. #endif
  435.             EndCollection(false); 
  436.         }
  437.         
  438.         AbortTrap();
  439.     }
  440.     Enable();
  441. }
  442.  
  443. /***************************************************************************/
  444.  
  445. void NewWindowPatch::NewWindowPatch()
  446. {
  447.     GenericPatch::InitGenericPatch(_NewWindow, offsetof(NewWindowParameters, itsResult));
  448.     Install();
  449. }
  450.  
  451. void NewWindowPatch::Behavior()
  452. {
  453.     if (theFileListGood && IsFinderRunning()) {
  454.         reg NewWindowParameters *parms = (NewWindowParameters*) itsFrame->parameters;
  455.         parms->itsResult = nil;
  456.         AbortTrap();
  457.     }
  458. }
  459.  
  460. void NewCWindowPatch::NewCWindowPatch()
  461. {
  462.     GenericPatch::InitGenericPatch(_NewCWindow, offsetof(NewWindowParameters, itsResult));
  463.     Install();
  464. }
  465.  
  466. void NewCWindowPatch::Behavior()
  467. {
  468.     if (theFileListGood && IsFinderRunning()) {
  469.         reg NewWindowParameters *parms = (NewWindowParameters*) itsFrame->parameters;
  470.         parms->itsResult = nil;
  471.         AbortTrap();
  472.     }
  473. }
  474.  
  475. /***************************************************************************/
  476.  
  477. void SystemTaskPatch::SystemTaskPatch()
  478. {
  479.     GenericPatch::InitGenericPatch(_SystemTask, 0);
  480.     Install();
  481. }
  482.  
  483. void SystemTaskPatch::Behavior()
  484. {
  485.     Disable();
  486.  
  487.     if (IsFinderRunning()) {
  488.         Boolean finderIsFront = GetFrontProcessCreator() == 'MACS';
  489.  
  490.         if (theCmdPeriodHit) {
  491.             theCmdPeriodHit = false;
  492.  
  493.             if (theCreator != 0)
  494.                 SendCancelledEvent(theCreator);
  495.         }
  496.  
  497.         if (theMenuBarDirty && finderIsFront) {
  498.             theMenuBarDirty = false;
  499.             HiliteMenu(0);
  500.             DrawMenuBar();
  501.         }
  502.  
  503.         if (theBeachBallRolling) {
  504.             if (finderIsFront) {
  505.                 theSetCursorPatch->Disable();
  506.                 SetCursor(GetNextCursor());
  507.                 theSetCursorPatch->Enable();
  508.             } else {
  509.                 EndCursor();
  510. //                InitCursor();  REMINDSMZ: switching back to Finder?
  511.             }
  512.         }
  513.     }
  514.  
  515.     Enable();
  516. }
  517.  
  518. /***************************************************************************/
  519.  
  520. DrawStringPatch::DrawStringPatch()
  521. {
  522.     GenericPatch::InitGenericPatch(_DrawString, offsetof(DrawStringParameters, bogusResult));
  523.     Install();
  524.     Disable();
  525. }
  526.  
  527. void DrawStringPatch::Behavior()
  528. {
  529.     Disable();
  530.  
  531.     if (theDrawingHappening > 0) {
  532.         reg DrawStringParameters* params = (DrawStringParameters*) itsFrame->parameters;
  533.  
  534.         if (IsSpecialString(params->itsString)) {
  535.             DrawSpecialString(params->itsString);
  536.             AbortTrap();
  537.         }
  538.     }
  539.  
  540.     Enable();
  541. }
  542.  
  543. /***************************************************************************/
  544.  
  545. StringWidthPatch::StringWidthPatch()
  546. {
  547.     GenericPatch::InitGenericPatch(_StringWidth, offsetof(StringWidthParameters, itsResult));
  548.     Install();
  549.     Disable();
  550. }
  551.  
  552. void StringWidthPatch::Behavior()
  553. {
  554.     Disable();
  555.  
  556.     if (theDrawingHappening > 0) {
  557.         reg StringWidthParameters* params = (StringWidthParameters*) itsFrame->parameters;
  558.         if (IsSpecialString(params->itsString)) {
  559.             params->itsResult = SpecialStringWidth(params->itsString);
  560.             AbortTrap();
  561.         }
  562.     }
  563.  
  564.     Enable();
  565. }
  566.  
  567. /***************************************************************************/
  568.  
  569. SetCursorPatch::SetCursorPatch()
  570. {
  571.     GenericPatch::InitGenericPatch(_SetCursor, offsetof(SetCursorParameters, dummy));
  572.     Install();
  573.     Disable();
  574. }
  575.  
  576. void SetCursorPatch::Behavior()
  577. {
  578.     Disable();
  579.  
  580.     if (theBeachBallRolling && IsFinderRunning())
  581.         AbortTrap();
  582.  
  583.     Enable();
  584. }
  585.  
  586. /***************************************************************************/
  587.  
  588. ParamTextPatch::ParamTextPatch()
  589. {
  590.     GenericPatch::InitGenericPatch(_ParamText, offsetof(ParamTextParameters, dummy));
  591.     Install();
  592.     Disable();
  593. }
  594.  
  595. void ParamTextPatch::Behavior()
  596. {
  597.     Disable();
  598.  
  599.     if (theFileListGood && IsFinderRunning()) {
  600.         reg ParamTextProcPtr oldParamText = (ParamTextProcPtr) itsOld;
  601.         
  602.         (*oldParamText)(nil, nil, nil, nil);
  603.  
  604.         AbortTrap();
  605.     }
  606.  
  607.     Enable();
  608. }
  609.  
  610. /***************************************************************************/
  611.  
  612. PostEventPatch::PostEventPatch()
  613. {
  614.     GenericPatch::InitGenericPatch(_PostEvent, 0);
  615.     Install();
  616.     Disable();
  617. }
  618.  
  619. short keys[] : 0x174;
  620.  
  621. void PostEventPatch::Behavior()
  622. {
  623.     Disable();
  624.  
  625.     switch ((short) itsFrame->ra0) {
  626.         case keyDown:
  627.             if ((keys[3] & 0x8000) != 0)
  628.                 if ((itsFrame->rd0 & 0x00ff) == '.') {
  629.                     theCmdPeriodHit = true;
  630.                     AbortTrap();
  631.                 }
  632.             break;
  633.     }
  634.     
  635.     Enable();
  636. }
  637.  
  638. /***************************************************************************/
  639.  
  640. static long DoDispatch(short selector, OSType creator, int va_alist)
  641. {
  642.     va_list args;
  643.     long rVal;
  644.     long tmp0;
  645.     long tmp1;
  646.     
  647.     OpenGlobals();
  648.  
  649.     if (! theWorldInit)
  650.         InitWorld();
  651.  
  652.     switch (selector) {
  653.         case eInitFinderMenu:
  654.             rVal = (long) DoInit(creator);
  655.             break;
  656.         case eAppendMenu:
  657.             va_start(args);
  658.             tmp0 = (long) va_arg(args, MenuHandle);
  659.             tmp1 = (long) va_arg(args, short);
  660.             rVal = (long) DoAppend(creator, (MenuHandle) tmp0, (short) tmp1);
  661.             va_end(args);
  662.             break;
  663.         case eDeleteMenus:
  664.             rVal = (long) DoDelete(creator);
  665.             break;
  666.         case eRemoveEntry:
  667.             rVal = (long) DoRemove(creator);
  668.             break;
  669.         case eClientFinished:
  670.             (void) DoClientDone(creator);
  671.             thePostEventPatch->Disable();    // turning off now
  672.             theParamTextPatch->Disable();
  673.             /* fall through to FreshMenubar */
  674.         case eFreshMenuBar:    // maybe next SystemTask…
  675.             theMenuBarDirty = true;
  676.             EndCursor();
  677.             rVal = true;
  678.             break;
  679.         case eRollBeachball:
  680.             StartCursor();
  681.             rVal = false;
  682.             break;
  683.         default: {
  684. #ifdef DEBUG
  685.             static char s[] = "\pX: selected!";
  686.             s[1] = 0x30 + selector;
  687.             DebugStr(s);
  688.             rVal = 0;
  689. #endif
  690.         }    break;
  691.     }
  692.     
  693.     CloseGlobals();
  694.     return rVal;
  695. }
  696.  
  697. #if __option(a4_globals)
  698.  
  699. static pascal OSErr GestaltFunction(OSType selector, long *response)
  700. {
  701.     OpenGlobals();
  702.     *response = (long) DoDispatch;
  703.     CloseGlobals();
  704.     return noErr;
  705. }
  706.  
  707. static Boolean InstallDispatcher(void)
  708. {
  709.     RememberGlobals();
  710.     if (NewGestalt(cGetFinderMenuProc, (ProcPtr) StripAddress(GestaltFunction)) != noErr) {
  711. #ifdef DEBUG
  712.         DebugStr("\pno gestalt!");
  713. #endif
  714.         return false;
  715.     }
  716.     return true;
  717. }
  718.  
  719. #else
  720.  
  721. struct Dummy {
  722.     long    x0;
  723.     long    x1;
  724.     short    x2;
  725.     long    address;
  726.     long    x4;
  727. } dummyProc = {
  728. //    0xa9ff225f,    _Debugger
  729.     0x4e71225f,
  730.     0x205f201f,
  731.     0x20bc,
  732.     0x00000000,
  733.     0x42574ed1
  734. };
  735.  
  736. static Boolean InstallDispatcher(void)
  737. {
  738.     reg struct Dummy *newProc = (struct Dummy *) NewPtrSys(sizeof(dummyProc));
  739.     ProcPtr oldToss;
  740.     
  741.     RememberGlobals();
  742.     
  743.     BlockMove(&dummyProc, newProc, sizeof(dummyProc));
  744.     newProc->address = (long) DoDispatch;
  745.     
  746.     if (NewGestalt(cGetFinderMenuProc, newProc) != noErr)
  747.         if (ReplaceGestalt(cGetFinderMenuProc, newProc, &oldToss) != noErr) {
  748.             DebugStr("\pno gestalt!");
  749.             return false;
  750.         }
  751.     return true;
  752. }
  753.  
  754. #endif
  755.  
  756.  
  757. /***************************************************************************/
  758.  
  759. void Install()
  760. {
  761. #ifdef DEBUG
  762.     if (*(short *) 0x100 != -1)
  763.         DebugStr("\ptrace carefully!");
  764.  
  765.     *(short *) 0x100 = 0x32;
  766. #endif
  767.  
  768.     try {
  769.         if (! System7Running()
  770.         ||  ! InstallDispatcher()
  771.         ||  ! LoadCursors()
  772.         ||  ! InitPrefsFile()
  773.         ) {
  774.             throw(memFullErr);
  775.         }
  776.  
  777.         new SystemTaskPatch;
  778.         new DrawMenuBarPatch;
  779.         new MenuSelectPatch;
  780.         new MenuKeyPatch;
  781.         new NewWindowPatch;
  782.         new NewCWindowPatch;
  783.  
  784.         theAlertPatch = new AlertPatch;
  785.         theFSDispatchPatch = new FSDispatchPatch;
  786.         theDrawStringPatch = new DrawStringPatch;
  787.         theStringWidthPatch = new StringWidthPatch;
  788.         theSetCursorPatch = new SetCursorPatch;
  789.         thePostEventPatch = new PostEventPatch;
  790.         theParamTextPatch = new ParamTextPatch;
  791.         
  792.         // if extension succeeds, show happy icon.
  793.         ShowIconFamily(128);
  794.     } /* try */
  795.  
  796.     catch {
  797.         // extension failed, show sad icon.
  798.         ShowIconFamily(129);
  799.         throw(theException);
  800.     }
  801. }
  802.  
  803. // called when system is shutdown.
  804.  
  805. void Remove()
  806. {    
  807.     Patch::RemoveAll();
  808. }
  809.